﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XWord.Fundamental.Domain.Services;
using XWord.WPF.ApplicationFramework;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting;
using System.Diagnostics;
using XWord.Fundamental.Domain;
using System.Collections;
using System.Timers;
using System.Threading;
using System.Runtime.Remoting.Channels.Tcp;
using XWord.Common;

namespace XWord.Remoting
{


    //[Serializable]
    //public class EtymaLibrary : Entity
    //{
    //    public virtual string Comment { get; set; }

    //    public virtual int WordIndex { get; set; }
    //}

    //public interface aa
    //{
    //}

    public class WordService : MarshalByRefObject, IWordService
    {
        
        public WordService()
        {
            System.Timers.Timer timer = new System.Timers.Timer(60000);
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
        }

        void CurrentDomain_ProcessExit(object sender, EventArgs e)
        {
            AutoUpdate();
        }
        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            AutoUpdate();
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }

        private Stopwatch _watch = Stopwatch.StartNew();

        private IList<string> _allWord;
        private readonly Dictionary<string, Hashtable> cacheHashtable = new Dictionary<string, Hashtable>();
        public string[] GetAllWord()
        {
            _watch.Start();
            if(_allWord==null)
                _allWord = BinaryFormatterHelper.Deserialize<IList<string>>
                    (BinaryFiles.BasePath + BinaryFiles.AllWordList);
            Console.WriteLine("GetAllWord Time {0}", _watch.Elapsed);
            _watch.Stop();
            return _allWord.ToArray();
        }

        public void WordAction(string word, int action)
        {
            if (action == 0)
            {
                _allWord.Add(word);
                Console.WriteLine("AddWord Time {0}", word);
            }
            if (action == 1)
            {
                Console.WriteLine("RemoveWord Time {0}", word);
                _allWord.Remove(word);
            }
        }

        private bool IsInAutoUpdate;
        public void AutoUpdate()
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback((object obj) =>
                {
                    _watch.Start();
                    lock (cacheHashtable)
                    {
                        IsInAutoUpdate = true;
                        foreach (var item in cacheHashtable)
                        {
                            Console.WriteLine("{0} AutoUpdate Time {1}", item.Key, _watch.Elapsed);
                            BinaryFormatterHelper.Serialize(BinaryFiles.BasePath + item.Key, item.Value);
                        }

                        BinaryFormatterHelper.Serialize(BinaryFiles.BasePath + BinaryFiles.AllWordList, _allWord);
                        BinaryFormatterHelper.Serialize(BinaryFiles.BasePath + BinaryFiles.AllEtymaLibraryList, _allEtymaLibraryList);
                        IsInAutoUpdate = false;
                        Console.WriteLine("AutoUpdate Time {0}", _watch.Elapsed);
                    }

                    _watch.Stop();
                }));
        }

        private IList<EtymaLibrary> _allEtymaLibraryList;
        public EtymaLibrary[] GetEtymaLibraryList()
        {
            _watch.Start();
            if (_allEtymaLibraryList == null)
                _allEtymaLibraryList = BinaryFormatterHelper.Deserialize<IList<EtymaLibrary>>
                    (BinaryFiles.BasePath + BinaryFiles.AllEtymaLibraryList);
            Console.WriteLine("GetEtymaLibraryList Time {0}", _watch.Elapsed);
            _watch.Stop();
            
            return _allEtymaLibraryList.ToArray();
        }

        public void SaveEtymaLibrary(string originName, EtymaLibrary etyma, int action)
        {
            while (IsInAutoUpdate)
            {   
            }
            switch (action)
            {
                case 0:
                    _allEtymaLibraryList.Add(etyma);
                    break;
                case 1:
                    var entity = _allEtymaLibraryList.FirstOrDefault(e => e.Name == originName);
                    if (entity.Name == originName)
                    {
                        var index = _allEtymaLibraryList.IndexOf(entity);
                        if (index >= 0)
                            _allEtymaLibraryList[index] = etyma;
                    }
                    break;
                case 2:
                    break;
            }
        }

        public Category[] GetCategoryList()
        {
            _watch.Start();
            var obj = BinaryFormatterHelper.Deserialize<IList<Category>>(BinaryFiles.BasePath + BinaryFiles.CategoryList);
            Console.WriteLine("GetObjFromBinaryFile Time {0}", _watch.Elapsed);
            _watch.Stop();
            return obj.ToArray();
        }

        public void CategoryWordAction(string word, int action)
        {
            while (IsInAutoUpdate)
            {
            }
            var categoryList=GetDataFromBinaryFile(BinaryFiles.CategoryList);
            if (action == 0)
            {
                _allWord.Add(word);
                Console.WriteLine("AddWord Time {0}", word);
            }
            if (action == 1)
            {
                Console.WriteLine("RemoveWord Time {0}", word);
                _allWord.Remove(word);
            }
        }

        public int[] GetWordStatisic()
        {
            _watch.Start();
            Console.WriteLine("GetWordStatisic Time {0}", _watch.Elapsed);
            var allWordList=GetAllWord();
            int wordCount = GetAllWord().Length;
            var examCriterion = GetDataFromBinaryFile(BinaryFiles.ExamCriterion);
            var notFamilarList=allWordList
                .Where(e => FilerNotFamilar(e, examCriterion[e] as Hashtable));
            var etymaWordExplains = GetDataFromBinaryFile(BinaryFiles.EtymaWordExplain);
            int notFamilarCount = notFamilarList.Count();
            var notEtymaList=allWordList
                .Where(e => FilerNotEtyma(e, etymaWordExplains[e] as Hashtable));
            int notEtymaCount = notEtymaList.Count();
            _watch.Stop();
            return new int[3] { wordCount, notFamilarCount, notEtymaCount };
        }

        private bool FilerNotFamilar(string word, Hashtable ht)
        {
            if (ht == null) return false;
            return !Convert.ToBoolean(ht["IsFamiliar"].ToString());
        }

        private bool FilerNotEtyma(string word, Hashtable ht)
        {
            if (ht == null) return false;
            return ht["Etyma"] == null || string.IsNullOrEmpty(ht["Etyma"].ToString());
        }

        public Alphabet[] GetAlphabetList()
        {
            _watch.Start();
            var AllAlphabetList = BinaryFormatterHelper.Deserialize<IList<Alphabet>>(BinaryFiles.BasePath + BinaryFiles.AlphabetList);
          
            //BinaryFormatterHelper.Serialize(BinaryFormatterHelper.Path + "AlphabetList.data", AllAlphabetList.ToArray());
            Console.WriteLine("AlphabetList Time {0}", _watch.Elapsed);
            _watch.Stop();
            return AllAlphabetList.ToArray();
        }

        public void SaveSingelEntity(string fileName, string key, object obj)
        {
            while (IsInAutoUpdate)
            {
            }
            _watch.Start();
            var ht = GetDataFromBinaryFile(fileName);
            if (obj == null && ht.ContainsKey(key))
            {
                ht.Remove(key);
            }
            else
            {
                ht[key] = obj;
            }
            _watch.Stop();
            Console.WriteLine("SaveSingelEntity fileName:{0} key:{1} Time {2}", fileName, key, _watch.Elapsed);
        }

        public Hashtable GetDataFromBinaryFile(string fileName)
        {
            _watch.Start();
            if (!cacheHashtable.ContainsKey(fileName))
            {
                cacheHashtable[fileName] = BinaryFormatterHelper.Deserialize<Hashtable>(BinaryFiles.BasePath + fileName);
            }

            Console.WriteLine("GetDataFromBinaryFile Time {0}", _watch.Elapsed);
            _watch.Stop();
            return cacheHashtable[fileName];
        }

        public void SaveGenericFile(string fileName, IList list)
        {

            BinaryFormatterHelper.Serialize(BinaryFiles.BasePath+fileName, list);
        }

        public void SaveBinaryFile(string fileName, object ht)
        {
            while (IsInAutoUpdate)
            {
            }
                try
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback((object obj) =>
                    {
                        _watch.Start();
                        if (ht is Hashtable)
                        {
                            cacheHashtable[fileName] = ht as Hashtable;
                        }
                        else
                        {
                            BinaryFormatterHelper.Serialize(BinaryFiles.BasePath + fileName, ht);
                        }
                        Console.WriteLine("SaveBinaryFile Time {0}", _watch.Elapsed);
                        _watch.Stop();
                    }));
                }
                catch (Exception e)
                {
                }
        }
    }
}
